using RestSharp;
using Serilog;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Net;
using System.Security.Cryptography;
using Newtonsoft.Json.Linq;
using Models;

namespace Bjts.ApiGate
{
  public class ApiResult<T>
  {
    public int Code { get; set; }
    public string Msg { get; set; }
    public T Data { get; set; }
  }

  public class ApiHelper
  {
    public static string UserKey { get; set; }
    public static ApiResult<T> GetApiResultEx<T>(string api, object parmInfo, Method method = Method.GET)
    {
      try
      {
        var result = GetApiResult<T>(api, parmInfo, method);
        return new ApiResult<T>()
        {
          Code = 0,
          Data = result
        };
      }
      catch (Exception ex)
      {
        return new ApiResult<T>()
        {
          Code = -1,
          Msg = ex.Message,
          Data = default(T)
        };
      }
    }

    public static Dictionary<string, object> GetApiResult(string api, object parmInfo, Method method = Method.GET)
    {
      var result = GetApiResult<Dictionary<string, object>>(api, parmInfo, method);
      if (result != null)
      {
        if (result.ContainsKey("details"))
        {
          var details = result["details"].ToString();
          var dict = new Dictionary<string, object>();
          dict.Add("code", result["statusCode"]);
          var msg = "接口异常";
          if (details.Contains("Network Interfaces, error: 26"))
          {
            msg = "数据库无法连接";
          }
          dict.Add("msg", msg); //result["details"]
          return dict;
        }
        if (result.ContainsKey("data"))
        {
          var data = new Dictionary<string, object>();
          if (TryCovertToDict(result["data"], out data))
          {
            result["data"] = data;
          }
          var data2 = new List<Dictionary<string, object>>();
          if (TryCovertToList(result["data"], out data2))
          {
            result["data"] = data2;
          }
        }
      }
      else
      {
        throw new ApiException("无法调用接口，响应超时", ApiError.ApiTimeout);
      }
      return result;
    }
    
    /// <summary>
    /// 调用接口
    /// 统一入口
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="api"></param>
    /// <param name="parmInfo"></param>
    /// <param name="method"></param>
    /// <returns></returns>
    public static T GetApiResult<T>(string api, object parmInfo, Method method = Method.GET)
    {
      RestClient client = null;
      RestRequest request = null;
      try
      {        
        var isJsonRequest = true;
        Dictionary<string, object> parms = new Dictionary<string, object>();
        if (parmInfo is Dictionary<string, object>)
        {
          var dict = parmInfo as Dictionary<string, object>;
          foreach (var item in dict)
          {
            parms.Add(item.Key, item.Value);
          }
          isJsonRequest = false;
        }
        else if (parmInfo is Dictionary<string, string>)
        {
          var dict = parmInfo as Dictionary<string, string>;
          foreach (var item in dict)
          {
            parms.Add(item.Key, item.Value);
          }
          isJsonRequest = false;
        }
        Log.Logger.Debug("正在调用平台接口：{0}", api);
        var currentUserIDKeyName = "currentUserID";

        string apiHost = SiteConfig.GetApiHost(parms["testUnitId"].ToString());

        if (string.IsNullOrEmpty(apiHost))
        {
          throw new ApiException("无法调用接口，接口地址未设置", ApiError.ApiConfigError);
        }
        client = new RestClient(apiHost);

        // 跳过 https 证书验证 
        ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;

        request = new RestRequest(api, method);
        var hasAddUserID = false;
        if (isJsonRequest)
        {
          method = Method.POST;
          request.Method = method;
          request.AddJsonBody(parmInfo);
        }
        else
        {
          if (method == Method.GET)
          {
            foreach (var p in parms)
            {
              if (p.Key.Equals(currentUserIDKeyName, StringComparison.CurrentCultureIgnoreCase))
              {
                if (p.Value == null || p.Value.ToString().Length == 0)
                {
                  continue;
                }
                hasAddUserID = true;
              }
              request.AddQueryParameter(p.Key, p.Value == null ? string.Empty : p.Value.ToString());
            }
          }
          else if (method == Method.POST)
          {
            foreach (var p in parms)
            {
              if (p.Key.Equals(currentUserIDKeyName, StringComparison.CurrentCultureIgnoreCase))
              {
                if (p.Value == null || p.Value.ToString().Length == 0)
                {
                  continue;
                }
                hasAddUserID = true;
              }
              request.AddParameter(p.Key, p.Value);
            }
          }
        }
        if (!hasAddUserID)
        {
          request.AddQueryParameter(currentUserIDKeyName, UserKey == null ? string.Empty : UserKey);
        }

        //生成随机数
        RandomNumberGenerator rng = RNGCryptoServiceProvider.Create();
        byte[] random = new Byte[8];
        rng.GetBytes(random);
        string NONCE = Math.Abs(BitConverter.ToInt64(random, 0)).ToString();
        string TIMESTAMP = ((long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds).ToString();
        //request.AddHeader("token", token);  
        request.AddHeader("serverip", GetIPAddress());
        request.AddHeader("nonce", NONCE);
        request.AddHeader("timestamp", TIMESTAMP);
        request.AddHeader(currentUserIDKeyName, UserKey == null ? string.Empty : UserKey);
        var apiKey = "1";
        if (!string.IsNullOrEmpty(apiKey))
        {
          request.AddHeader("apikey", apiKey);
          request.AddQueryParameter("apikey", apiKey);
        }
      }
      catch (Exception ex)
      {
        Log.Logger.Error("调用平台接口异常：{0}", ex.Message);
        throw new ApiException(ex.Message, ApiError.ApiRequestError);
      }
      IRestResponse response = null;
      try
      {
        response = client.Execute(request);
        var json = new RestSharp.Serialization.Json.JsonSerializer();
        var r = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(response.Content);
        return r;
      }
      catch (Exception ex)
      {
        var msg = string.Format("调用平台接口响应出错[{0}，{1}]：{2}\r\n{3}", response.StatusCode,
            response.ErrorMessage, response.Content, ex.Message);
        Log.Logger.Error(msg);
        var exMsg = msg;
        ApiError code = ApiError.ApiResponseError;
        if (response.StatusCode == HttpStatusCode.Unauthorized)
        {
          code = ApiError.ApiUnauthorized;
          exMsg = "未授权，请检查ApiKey是否设置正确";
        }
        else if (response.StatusCode == HttpStatusCode.InternalServerError)
        {
          code = ApiError.ApiInternalServerError;
          exMsg = "接口500错误：" + response.Content;
        }
        else if (response.StatusCode == 0)
        {
          code = ApiError.ApiTimeout;
          exMsg = "调用接口超时";
        }
        throw new ApiException(exMsg, code);
      }

    }
   

    public static string GetIPAddress()
    {
      IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName()); // `Dns.Resolve()` method is deprecated.
      IPAddress ipAddress = ipHostInfo.AddressList[0];
      return ipAddress.ToString();
    }

    public static bool TryCovertToList(object data, out List<Dictionary<string, object>> result)
    {
      if (data != null)
      {
        var obj = data as JArray;
        if (obj != null)
        {
          result = obj.ToObject<List<Dictionary<string, object>>>();
          return true;
        }
      }
      result = null;
      return false;
    }

    public static bool TryCovertToDict(object data, out Dictionary<string, object> result)
    {
      if (data != null)
      {
        var obj = data as JObject;
        if (obj != null)
        {
          result = obj.ToObject<Dictionary<string, object>>();
          return true;
        }
      }
      result = null;
      return false;
    }

    public static Dictionary<string, object> CovertToDict(object data)
    {
      if (data is Dictionary<string, object>) return data as Dictionary<string, object>;
      if (data == null) return new Dictionary<string, object>();
      var obj = data as JObject;
      if (obj == null) return new Dictionary<string, object>();
      return obj.ToObject<Dictionary<string, object>>();
    }

    public static List<Dictionary<string, object>> CovertToList(object data)
    {
      if (data is List<Dictionary<string, object>>) return data as List<Dictionary<string, object>>;
      if (data == null) return new List<Dictionary<string, object>>();
      var array = data as JArray;
      if (array == null) return new List<Dictionary<string, object>>();
      return array.ToObject<List<Dictionary<string, object>>>();
    }

    public static List<Dictionary<string, object>> CovertToList(JsonArray array)
    {
      List<Dictionary<string, object>> list = new List<Dictionary<string, object>>();
      if (array == null) return list;
      foreach (Dictionary<string, object> item in array)
      {
        list.Add(item);
      }
      return list;
    }
  }
}
